This is an R Markdown
Notebook. When you execute code within the notebook, the results appear
beneath the code.
Try executing this chunk by clicking the Run button within
the chunk or by placing your cursor inside it and pressing
Cmd+Shift+Enter.
plot(cars)
Add a new chunk by clicking the Insert Chunk button on the
toolbar or by pressing Cmd+Option+I.
When you save the notebook, an HTML file containing the code and
output will be saved alongside it (click the Preview button or
press Cmd+Shift+K to preview the HTML file).
The preview shows you a rendered HTML copy of the contents of the
editor. Consequently, unlike Knit, Preview does not
run any R code chunks. Instead, the output of the chunk when it was last
run in the editor is displayed.
**************************************
PART FOUR: CLASS EXERCISES *
**************************************
Jon Sadler - updated Mar 10th 2022
load in Libraries
library(car)
Loading required package: carData
library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
method from
print.tbl_lazy
print.tbl_sql
Warning in (function (kind = NULL, normal.kind = NULL, sample.kind = NULL) :
non-uniform 'Rounding' sampler used
── Attaching packages ─────────────────────────────────────────────── tidyverse 1.3.1 ──
✓ ggplot2 3.3.5 ✓ purrr 0.3.4
✓ tibble 3.1.6 ✓ dplyr 1.0.8
✓ tidyr 1.2.0 ✓ stringr 1.4.0
✓ readr 2.1.2 ✓ forcats 0.5.1
Warning in (function (kind = NULL, normal.kind = NULL, sample.kind = NULL) :
non-uniform 'Rounding' sampler used
── Conflicts ────────────────────────────────────────────────── tidyverse_conflicts() ──
x dplyr::filter() masks stats::filter()
x dplyr::lag() masks stats::lag()
x dplyr::recode() masks car::recode()
x purrr::some() masks car::some()
library(ggfortify)
library(scales) # You need this library to to access break formatting functions for log axes
Attaching package: ‘scales’
The following object is masked from ‘package:purrr’:
discard
The following object is masked from ‘package:readr’:
col_factor
#1. Linear Regression using the faithful dataset # look at the data
in the base file
str(faithful)
'data.frame': 272 obs. of 2 variables:
$ eruptions: num 3.6 1.8 3.33 2.28 4.53 ...
$ waiting : num 79 54 74 62 85 55 88 85 51 85 ...
faithful
View(faithful)
plot some pictures
scatterplot(eruptions ~ waiting, data = faithful)

Looks decent in terms of the boxplots - indicates normality and
homogeneity of variance
Maybe an issue with linearity of the response to explanatory but
we’ll have a look
Using ggplot
ggplot(faithful,aes(waiting,eruptions)) + geom_point() + geom_smooth(method=lm)
`geom_smooth()` using formula 'y ~ x'

Specify and examine linear model
summary(lm(eruptions ~ waiting, data = faithful))
Call:
lm(formula = eruptions ~ waiting, data = faithful)
Residuals:
Min 1Q Median 3Q Max
-1.29917 -0.37689 0.03508 0.34909 1.19329
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -1.874016 0.160143 -11.70 <2e-16 ***
waiting 0.075628 0.002219 34.09 <2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.4965 on 270 degrees of freedom
Multiple R-squared: 0.8115, Adjusted R-squared: 0.8108
F-statistic: 1162 on 1 and 270 DF, p-value: < 2.2e-16
anova(lm(eruptions ~ waiting, data = faithful))
Analysis of Variance Table
Response: eruptions
Df Sum Sq Mean Sq F value Pr(>F)
waiting 1 286.478 286.478 1162.1 < 2.2e-16 ***
Residuals 270 66.562 0.247
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
write the model to an object
faithful.lm <- lm(eruptions ~ waiting, data = faithful)
look at plots for validation
op <- par(mfrow = c(2, 2))
plot(faithful.lm)
par(op)

QQ-plot indicates normality
residuals v fitted suggests limited heterogeneity that is a result
of two clumps of points, but it the residuals are evenly spread either
side of the zero line.
Scale v location indicates homogeneity
Leverage plot indicates a few issues. We’ll leave it and come back
to how to deal with this # in subsequent classes
same plots in ggfortify
autoplot(faithful.lm)

Last validation task; plot residuals against explanatory
plot(faithful.lm$resid ~ faithful$waiting,
xlab = "Waiting time (mins)",
ylab = "Model residuals")

Generally fine so we’ll go with it for the time being.
Decision will run with a linear model
# We’ll revisit this in a week or so to run another regression
technique later in the course # plot model and add R-square etc
plot(eruptions ~ waiting, data = faithful,
xlab = "Waiting time between eruptions (mins)",
ylab = "Eruption duration (mins)",
pch = 20, col = "grey", bg = "grey") # We've left the axes on
# add the regression line from the model (faithful.lm) using abline.....
abline(faithful.lm, col="black")
# add the equation
text(99,2, "eruptions = 0.0756waiting + -1.874", pos = 2, cex=0.65)
# add r-square value
text(99,1.75, expression(paste(R^2 == 0.8108)), pos = 2, cex = 0.6) # add in text using the expression/paste functions
# create a sequence of 1000 number spanning the range of humidities (min to max)
x <- seq(min(faithful$waiting), max(faithful$waiting), l=1000) # notice this is an 'l' = length. NOT a 1!!!!!!!
#for each value of x, calculate the upper and lower 95% confidence
y<-predict(faithful.lm, data.frame(waiting=x), interval="c")
#plot the upper and lower 95% confidence limits
matlines(x,y, lty=3, col="black") # This function add the CIs, lty = line type (dashed)

plot with ggplot
p <- ggplot(faithful, aes(x=waiting, y=eruptions)) +
geom_point(col = "grey") +
geom_smooth(method=lm, col = "black") +
annotate(geom = "text", x = 50, y = 6,
label = "Eruptions = -0.076Waiting + -1.87\nAdj. R2 = 0.8108",
hjust = 0)
p + xlab("Waiting time between eruptions (mins)") + ylab("Eruption duration (mins)") + theme_bw()
`geom_smooth()` using formula 'y ~ x'

Predict and plot with ggplot
add ‘fit’, ‘lwr’, and ‘upr’ columns to dataframe (generated by
predict)
old.predict <- cbind(faithful, predict(faithful.lm, interval = 'confidence'))
plot the points (actual observations), regression line, and
confidence interval
p <- ggplot(old.predict, aes(waiting,eruptions))
p <- p + geom_point()
p <- p + geom_line(aes(waiting, fit))
p <- p + geom_ribbon(aes(ymin=lwr,ymax=upr), alpha=0.3)
p

2. Mussel dataset using abundance as a response variable
load data file
Mussel <- read.csv(file.choose())
Look at it
glimpse(Mussel)
Rows: 25
Columns: 3
$ AREA <dbl> 516.00, 469.06, 462.25, 938.60, 1357.15, 1773.66, 1686.01, 1786.29, 30…
$ SPECIES <int> 3, 7, 6, 8, 10, 9, 10, 11, 16, 9, 13, 14, 12, 14, 20, 22, 15, 20, 22, …
$ INDIV <int> 18, 60, 57, 100, 48, 118, 148, 214, 225, 283, 380, 278, 338, 274, 569,…
Plot it to check for linearity
scatterplot(INDIV ~ AREA, data = Mussel)

This indicates that the data are not normaly disributed (especially
AREA)
The abundance data don’t look too good either. Huge peak in the
middle
might be outliers in both!!!!
Let’s fit a linear model nonetheless
mussel.lm <- lm(SPECIES ~ AREA, data = Mussel)
# look at it
summary(mussel.lm)
Call:
lm(formula = SPECIES ~ AREA, data = Mussel)
Residuals:
Min 1Q Median 3Q Max
-7.1964 -2.7521 -0.7509 1.2094 7.2148
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 9.856e+00 1.044e+00 9.441 2.24e-09 ***
AREA 6.593e-04 9.283e-05 7.102 3.10e-07 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 3.759 on 23 degrees of freedom
Multiple R-squared: 0.6868, Adjusted R-squared: 0.6732
F-statistic: 50.44 on 1 and 23 DF, p-value: 3.102e-07
Area looks to significantly related to the number of mussels
Now check assumption by using R’s inbuilt model validation plot
defaults
set graphics parameters because we want all the plots on one
graphic
autoplot(mussel.lm)

Residuals v Fitted indicate a problem. It’s wedge shaped and
humped!
qqplot is a bit dodgy but might be okay
Scale-Location plot indicates a wedge
Cook distance / leverage looks okay - but there are some large
values in area
FINAL VALIDATION TASK - residuals against explanatory variable
plot(mussel.lm$resid ~ Mussel$AREA,
xlab = "Mussel bed Area",
ylab = "Residuals")

Some code for ggplot to do the same thing…..
ggplot(fortify(mussel.lm, Mussel), aes(AREA, .stdresid)) +
geom_point() + geom_smooth(se = TRUE)
`geom_smooth()` using method = 'loess' and formula 'y ~ x'

This indicates a few large values and a slight wedge due to numerous
small patches
Conclusion we reject the model
So what do we do?
We can linearise the explanatory variables by transforming them and
re-run the model
I am not a fan of this - we’ll look at other approaches next
week!
and repeat the validation
Let’s fit a linear model nonetheless
mussel.lm1 <- lm(SPECIES ~ log10(AREA), data = Mussel)
# look at it
summary(mussel.lm1)
Call:
lm(formula = SPECIES ~ log10(AREA), data = Mussel)
Residuals:
Min 1Q Median 3Q Max
-5.7204 -1.7227 0.3603 1.8136 4.2430
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -25.731 3.777 -6.812 6.02e-07 ***
log10(AREA) 11.226 1.030 10.895 1.48e-10 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 2.707 on 23 degrees of freedom
Multiple R-squared: 0.8377, Adjusted R-squared: 0.8306
F-statistic: 118.7 on 1 and 23 DF, p-value: 1.481e-10
Now check assumption by using R’s inbuilt model validation plot
defaults
set graphics parameters because we want all the plots on one
graphic
autoplot(mussel.lm1)

Residuals v Fitted are better but there is still a bit of wedge at
higher fitted values
qqplot is a better
Scale-Location plot indicates a slight wedge with higher values
Cook distance / leverage looks improved
FINAL VALIDATION TASK - residuals against explanatory variable
ggplot(fortify(mussel.lm1, Mussel), aes(AREA, .stdresid)) +
geom_point() + geom_smooth(se = FALSE)
`geom_smooth()` using method = 'loess' and formula 'y ~ x'

This indicates a few large values and a slight wedge due to numerous
small patches
Conclusion we reject the model
Try log10 on the response - not unusual with abundance data.
There are no zeros so we don’t need an offset of 0.01 or something
similar
Let’s fit a linear model nonetheless
mussel.lm2 <- lm(log10(INDIV) ~ log10(AREA), data = Mussel)
# look at it
summary(mussel.lm2)
Call:
lm(formula = log10(INDIV) ~ log10(AREA), data = Mussel)
Residuals:
Min 1Q Median 3Q Max
-0.43355 -0.06464 0.02219 0.11178 0.26818
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.57601 0.25904 -2.224 0.0363 *
log10(AREA) 0.83492 0.07066 11.816 3.01e-11 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.1856 on 23 degrees of freedom
Multiple R-squared: 0.8586, Adjusted R-squared: 0.8524
F-statistic: 139.6 on 1 and 23 DF, p-value: 3.007e-11
Now check assumption
autoplot(mussel.lm2)

Residuals v Fitted are much better
qqplot is okay - slight issue on lower values
Scale-Location plot is fine
Cook distance / leverage looks okay
FINAL VALIDATION TASK - residuals against explanatory variable
ggplot(fortify(mussel.lm2, Mussel), aes(AREA, .stdresid)) +
geom_point()

This is better but still a slight hump
Conclusion we accept the model
plot the final model in ggplot…
p <- ggplot(Mussel, aes(AREA,INDIV)) +
geom_point(col = "grey") +
geom_smooth(method=lm, col = "black") +
annotate(geom = "text", x = 1000, y = 30,
label = "log10(INDIV) = 0.835 + log10(AREA) - 0.576\n[Adj. R2 = 0.8108]", hjust = 0) # adds text (NOTE \n means start new line)
p + scale_x_continuous(trans = 'log10') + scale_y_continuous(trans = 'log10') + # These commands scale the axes
annotation_logticks(sides="lb") # This adds log10 tick marks
`geom_smooth()` using formula 'y ~ x'

NOTE: the log axes use the Scales library [see above]
#Plot the graph add equations in base R
plot(log10(INDIV) ~ log10(AREA), data = Mussel,
xlab = "Log Mussel clump area (mm2)",
ylab = "Log Number of Individuals",
pch = 21, col = "grey", bg = "grey") # We've left the axes on
# add the regression line from the model (faithful.lm) using abline.....
abline(mussel.lm2, col="black")
# add the equation
text(4.0, 1.4, expression(paste(Log[10], "INDIV = 0.835", log[10], "AREA - 0.576", pos = 2)), cex = .7)
# add r-square value
text(4.0, 1.3, expression(paste(R^2 == 0.852)), cex = .7) # add in text using the expression/paste functions
# create a sequence of 1000 number spanning the range of humidities (min to max)
x <- seq(min(Mussel$AREA), max(Mussel$AREA), l=1000) # notice this is an 'l' = length. NOT a 1!!!!!!!
#for each value of x, calculate the upper and lower 95% confidence
y<-predict(mussel.lm2, data.frame(AREA=x), interval="c")
#plot the upper and lower 95% confidence limits
matlines(log10(x),y, lty=3, col="black") # This function add the CIs, lty = line type (dashed)

add in ggplot code….
p <- ggplot(Mussel, aes(x=log10(AREA), y=log10(INDIV))) +
geom_point(col = "blue") +
geom_smooth(method=lm, col = "black") +
annotate(geom = "text", x = 2.5, y = 3,
label = "Log10INDIV = 0.835 + log10AREA - 0.576\nAdj. R2 = 0.852",
hjust = 0)
p + xlab("Log Mussel clump area (mm2)") + ylab("Log number of individuals")
`geom_smooth()` using formula 'y ~ x'

3. ANCOVA on compensation dataset
Just so you have a frame of reference going forward;
the compensation data are about the production of fruit (apples,
kg)
on rootstocks of different widths (mm; the tops are grafted onto
rootstocks).
Furthermore, some trees are in parts of the orchard that allow
grazing by cattle,
and others are in parts free from grazing. Grazing may reduce the
amount of grass,
which might compete with the apple trees for resources.
Load file
Compensation <- read.csv(file.choose())
look at data
str(Compensation)
'data.frame': 40 obs. of 3 variables:
$ Root : num 6.22 6.49 4.92 5.13 5.42 ...
$ Fruit : num 59.8 61 14.7 19.3 34.2 ...
$ Grazing: Factor w/ 2 levels "Grazed","Ungrazed": 2 2 2 2 2 2 2 2 2 2 ...
Compensation$Grazing <- as.factor(Compensation$Grazing) # We need this to be a factor for an ANCOVA
Plot it
# Plot it....
plot(Fruit ~ Root, data = Compensation, pch = 19,cex = 1.5,
col = c("Black", "Red")[Compensation$Grazing],
xlab = list("Root biomass (mm)", cex = 1.2),
ylab = list("Fruit Production (kg)", cex = 1.2))
# Now add a legend
legend(5, 115, legend = c("Grazed", "Ungrazed"),
col = c("black", "red"), pch = 19)

Or in coplot
coplot(Root~ Fruit | Grazing, data =Compensation) # Grazed plants have higher root biomass.

You can do this is lattice too
boxplot(Root ~ Grazing, data = Compensation) # These look fine

boxplot(Fruit ~ Grazing, data = Compensation)# These look fine

You might also do some QQ-plots here…..or plot to check homogeneity
of variances
but we’ll leave that for validation….
Run ANCOVA
Compensation.lm <- lm(Fruit ~ Grazing*Root, data=Compensation)
Validate model to check assumptions
autoplot(Compensation.lm)

This looks pretty decent. Slight concern over QQ-plot but it’s not a
massive problem.
#Look at model outcomes
anova(Compensation.lm)
Analysis of Variance Table
Response: Fruit
Df Sum Sq Mean Sq F value Pr(>F)
Grazing 1 2910.4 2910.4 62.3795 2.262e-09 ***
Root 1 19148.9 19148.9 410.4201 < 2.2e-16 ***
Grazing:Root 1 4.8 4.8 0.1031 0.75
Residuals 36 1679.6 46.7
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Anova shows that both Root and Fruit are significant terms
But that the interaction isn’t….
summary(Compensation.lm)
Call:
lm(formula = Fruit ~ Grazing * Root, data = Compensation)
Residuals:
Min 1Q Median 3Q Max
-17.3177 -2.8320 0.1247 3.8511 17.1313
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -125.173 12.811 -9.771 1.15e-11 ***
GrazingUngrazed 30.806 16.842 1.829 0.0757 .
Root 23.240 1.531 15.182 < 2e-16 ***
GrazingUngrazed:Root 0.756 2.354 0.321 0.7500
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 6.831 on 36 degrees of freedom
Multiple R-squared: 0.9293, Adjusted R-squared: 0.9234
F-statistic: 157.6 on 3 and 36 DF, p-value: < 2.2e-16
Data indicate fruit differs by grazing
No interaction term i.e. slope for factor Grazing are the same
Look at the example in the lecture 6 to figure out the intercept and
slope differences, but here we go:
The intercept (first row in the summary output) is the intercept for
grazed samples because grazed (i.e G)
comes before ungrazed (i.e. U) in the alphabet and R uses an
alphanumeric call on factor data.
The 2nd line GrazingUngrazed is the difference in the intercepts. So
Ungrazed is 30.806 larger. Meaning 30.8 more seeds are produced by
grazed plants
Calculate the intercept for Ungrazed
-125.173 + 30.806 # = -94.367
[1] -94.367
the third line is slope for root
the fourth line GrazingUngrazed:Root is the difference in slopes
between Grazed and Ungrazed = 0.756, which is tiny
the coefficients show this….
coef(Compensation.lm)
(Intercept) GrazingUngrazed Root GrazingUngrazed:Root
-125.1730569 30.8057049 23.2403732 0.7560338
Now lets add lines to the graphs. We can do it many ways - so here
is another one!
Route one - using abline
plot(Fruit ~ Root, data = Compensation, pch = 19,cex = 1.5,
col = c("Black", "Red")[Compensation$Grazing],
xlab = list("Root biomass (mm)", cex = 1.2),
ylab = list("Fruit production (kg)", cex = 1.2))
# Now add a legend
legend(5, 115, legend = c("Grazed", "Ungrazed"),
col = c("black", "red"), pch = 19)
# add ablines....we'll do it manually using the slopes and intercepts but you can use coeff7() see below.
abline(-125.173, 23.240)
abline(-125.173+30.805, 23.240+0.756, col= "red")

Plot using coefficients
Compensation.lm$coeff[1] # regression coefficient for grazed intercept
(Intercept)
-125.1731
Compensation.lm$coeff[2] # regression coefficient for grazed slope
GrazingUngrazed
30.8057
Compensation.lm$coeff[3] # regression coefficient for diff in grazed/ungrazed intercept
Root
23.24037
Compensation.lm$coeff[4] # regression coefficient for diff in grazed/ungrazed slope
GrazingUngrazed:Root
0.7560338
plot(Fruit ~ Root, data = Compensation, pch = 19,cex = 1.5,
col = c("Black", "Red")[Compensation$Grazing],
xlab = list("Root biomass (mm)", cex = 1.2),
ylab = list("Fruit Production (kg)", cex = 1.2))
# Now add a legend
legend(5, 115, legend = c("Grazed", "Ungrazed"),
col = c("black", "red"), pch = 19)
# add ablines....using coefficients - coeff()
abline(coef(Compensation.lm)[1], coef(Compensation.lm)[3])
# Now add the summer regression line
abline(coef(Compensation.lm)[1] + coef(Compensation.lm)[2],
coef(Compensation.lm)[3] + coef(Compensation.lm)[4],
col = "red")

do some prediction….and plot….this is yet another way of doing
it
#produce base plot
xs <- seq(0, 12, l = 100)
plot(Fruit ~ Root, data = Compensation, xlab = "Root biomass (mm)", ylab = "Fruit Production (kg)")
# Plot the points and predicted trends (using se)
points(Fruit ~ Root, data = Compensation, subset = Grazing == "Grazed", pch = 19)
pred <- predict(Compensation.lm, type = "response", se = TRUE, newdata = data.frame(Root = xs, Grazing = "Grazed", Root = mean(Compensation$Root)))
lines(pred$fit ~ xs)
points(Fruit ~ Root, data = Compensation, subset = Grazing == "Ungrazed", pch = 19, col = "red")
pred <- predict(Compensation.lm, type = "response", se = TRUE, newdata = data.frame(Root = xs, Grazing = "Ungrazed", Root = mean(Compensation$Root)))
lines(pred$fit ~ xs, col = "red")
legend("topleft", legend = c("Grazed", "Ungrazed"), pch = c(19, 19), col = c("red","black"), title = "Fruit Production", bty = "n")
box(bty = "l")

Plot the points and predicted trends (using ggplot2). A fair bit
easier…..NOTE - you’d need to tidy up the labels and the like…
ggplot(Compensation, aes(x=Root, y=Fruit, color=factor(Grazing))) +
geom_point() +
geom_smooth(method=lm)
`geom_smooth()` using formula 'y ~ x'

LS0tCnRpdGxlOiAiTGluZWFyIFJlZ3Jlc3Npb24gQ29kZSB3YWxrdGhyb3VnaCIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKVGhpcyBpcyBhbiBbUiBNYXJrZG93bl0oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbSkgTm90ZWJvb2suIFdoZW4geW91IGV4ZWN1dGUgY29kZSB3aXRoaW4gdGhlIG5vdGVib29rLCB0aGUgcmVzdWx0cyBhcHBlYXIgYmVuZWF0aCB0aGUgY29kZS4gCgpUcnkgZXhlY3V0aW5nIHRoaXMgY2h1bmsgYnkgY2xpY2tpbmcgdGhlICpSdW4qIGJ1dHRvbiB3aXRoaW4gdGhlIGNodW5rIG9yIGJ5IHBsYWNpbmcgeW91ciBjdXJzb3IgaW5zaWRlIGl0IGFuZCBwcmVzc2luZyAqQ21kK1NoaWZ0K0VudGVyKi4gCgpgYGB7cn0KcGxvdChjYXJzKQpgYGAKCkFkZCBhIG5ldyBjaHVuayBieSBjbGlja2luZyB0aGUgKkluc2VydCBDaHVuayogYnV0dG9uIG9uIHRoZSB0b29sYmFyIG9yIGJ5IHByZXNzaW5nICpDbWQrT3B0aW9uK0kqLgoKV2hlbiB5b3Ugc2F2ZSB0aGUgbm90ZWJvb2ssIGFuIEhUTUwgZmlsZSBjb250YWluaW5nIHRoZSBjb2RlIGFuZCBvdXRwdXQgd2lsbCBiZSBzYXZlZCBhbG9uZ3NpZGUgaXQgKGNsaWNrIHRoZSAqUHJldmlldyogYnV0dG9uIG9yIHByZXNzICpDbWQrU2hpZnQrSyogdG8gcHJldmlldyB0aGUgSFRNTCBmaWxlKS4gCgpUaGUgcHJldmlldyBzaG93cyB5b3UgYSByZW5kZXJlZCBIVE1MIGNvcHkgb2YgdGhlIGNvbnRlbnRzIG9mIHRoZSBlZGl0b3IuIENvbnNlcXVlbnRseSwgdW5saWtlICpLbml0KiwgKlByZXZpZXcqIGRvZXMgbm90IHJ1biBhbnkgUiBjb2RlIGNodW5rcy4gSW5zdGVhZCwgdGhlIG91dHB1dCBvZiB0aGUgY2h1bmsgd2hlbiBpdCB3YXMgbGFzdCBydW4gaW4gdGhlIGVkaXRvciBpcyBkaXNwbGF5ZWQuCgojICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqCiMgUEFSVCBGT1VSOiBDTEFTUyBFWEVSQ0lTRVMgICAgICAgICAgICoKIyAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKgojIEpvbiBTYWRsZXIgLSB1cGRhdGVkIE1hciAxMHRoIDIwMjIKCmxvYWQgaW4gTGlicmFyaWVzCmBgYHtyfQpsaWJyYXJ5KGNhcikKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZ2dmb3J0aWZ5KQpsaWJyYXJ5KHNjYWxlcykgIyBZb3UgbmVlZCB0aGlzIGxpYnJhcnkgdG8gdG8gYWNjZXNzIGJyZWFrIGZvcm1hdHRpbmcgZnVuY3Rpb25zIGZvciBsb2cgYXhlcwpgYGAKCiMxLiBMaW5lYXIgUmVncmVzc2lvbiB1c2luZyB0aGUgZmFpdGhmdWwgZGF0YXNldAojIGxvb2sgYXQgdGhlIGRhdGEgaW4gdGhlIGJhc2UgZmlsZQpgYGB7cn0Kc3RyKGZhaXRoZnVsKQpmYWl0aGZ1bApWaWV3KGZhaXRoZnVsKQpgYGAKCiMgcGxvdCBzb21lIHBpY3R1cmVzCmBgYHtyfQpzY2F0dGVycGxvdChlcnVwdGlvbnMgfiB3YWl0aW5nLCBkYXRhID0gZmFpdGhmdWwpCmBgYAoKIyBMb29rcyBkZWNlbnQgaW4gdGVybXMgb2YgdGhlIGJveHBsb3RzIC0gaW5kaWNhdGVzIG5vcm1hbGl0eSBhbmQgaG9tb2dlbmVpdHkgb2YgdmFyaWFuY2UKIyBNYXliZSBhbiBpc3N1ZSB3aXRoIGxpbmVhcml0eSBvZiB0aGUgcmVzcG9uc2UgdG8gZXhwbGFuYXRvcnkgYnV0IHdlJ2xsIGhhdmUgYSBsb29rCgojIFVzaW5nIGdncGxvdApgYGB7cn0KZ2dwbG90KGZhaXRoZnVsLGFlcyh3YWl0aW5nLGVydXB0aW9ucykpICsgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgobWV0aG9kPWxtKQpgYGAKCiMgU3BlY2lmeSBhbmQgZXhhbWluZSBsaW5lYXIgbW9kZWwKYGBge3J9CnN1bW1hcnkobG0oZXJ1cHRpb25zIH4gd2FpdGluZywgZGF0YSA9IGZhaXRoZnVsKSkKYW5vdmEobG0oZXJ1cHRpb25zIH4gd2FpdGluZywgZGF0YSA9IGZhaXRoZnVsKSkKYGBgCiMgd3JpdGUgdGhlIG1vZGVsIHRvIGFuIG9iamVjdApgYGB7cn0KZmFpdGhmdWwubG0gPC0gbG0oZXJ1cHRpb25zIH4gd2FpdGluZywgZGF0YSA9IGZhaXRoZnVsKQpgYGAKCiMgbG9vayBhdCBwbG90cyBmb3IgdmFsaWRhdGlvbgpgYGB7cn0Kb3AgPC0gcGFyKG1mcm93ID0gYygyLCAyKSkgCnBsb3QoZmFpdGhmdWwubG0pCnBhcihvcCkKYGBgCiMgUVEtcGxvdCBpbmRpY2F0ZXMgbm9ybWFsaXR5CiMgcmVzaWR1YWxzIHYgZml0dGVkIHN1Z2dlc3RzIGxpbWl0ZWQgaGV0ZXJvZ2VuZWl0eSB0aGF0IGlzIGEgcmVzdWx0IG9mIHR3byBjbHVtcHMgb2YgcG9pbnRzLCBidXQgaXQgdGhlIHJlc2lkdWFscyBhcmUgZXZlbmx5IHNwcmVhZCBlaXRoZXIgc2lkZSBvZiB0aGUgemVybyBsaW5lLgojIFNjYWxlIHYgbG9jYXRpb24gaW5kaWNhdGVzIGhvbW9nZW5laXR5CiMgTGV2ZXJhZ2UgcGxvdCBpbmRpY2F0ZXMgYSBmZXcgaXNzdWVzLiBXZSdsbCBsZWF2ZSBpdCBhbmQgY29tZSBiYWNrIHRvIGhvdyB0byBkZWFsIHdpdGggdGhpcyAjIGluIHN1YnNlcXVlbnQgY2xhc3NlcwoKIyBzYW1lIHBsb3RzIGluIGdnZm9ydGlmeQoKYGBge3J9CmF1dG9wbG90KGZhaXRoZnVsLmxtKQpgYGAKCiMgTGFzdCB2YWxpZGF0aW9uIHRhc2s7IHBsb3QgcmVzaWR1YWxzIGFnYWluc3QgZXhwbGFuYXRvcnkKYGBge3J9CnBsb3QoZmFpdGhmdWwubG0kcmVzaWQgfiBmYWl0aGZ1bCR3YWl0aW5nLAogICAgIHhsYWIgPSAiV2FpdGluZyB0aW1lIChtaW5zKSIsCiAgICAgeWxhYiA9ICJNb2RlbCByZXNpZHVhbHMiKQpgYGAKCiMgR2VuZXJhbGx5IGZpbmUgc28gd2UnbGwgZ28gd2l0aCBpdCBmb3IgdGhlIHRpbWUgYmVpbmcuIAoKIyBEZWNpc2lvbiB3aWxsIHJ1biB3aXRoIGEgbGluZWFyIG1vZGVsCiPCoFdlJ2xsIHJldmlzaXQgdGhpcyBpbiBhIHdlZWsgb3Igc28gdG8gcnVuIGFub3RoZXIgcmVncmVzc2lvbiB0ZWNobmlxdWUgbGF0ZXIgaW4gdGhlIGNvdXJzZQojIHBsb3QgbW9kZWwgYW5kIGFkZCBSLXNxdWFyZSBldGMKYGBge3J9CnBsb3QoZXJ1cHRpb25zIH4gd2FpdGluZywgZGF0YSA9IGZhaXRoZnVsLAogICAgIHhsYWIgPSAiV2FpdGluZyB0aW1lIGJldHdlZW4gZXJ1cHRpb25zIChtaW5zKSIsCiAgICAgeWxhYiA9ICJFcnVwdGlvbiBkdXJhdGlvbiAobWlucykiLAogICAgIHBjaCA9IDIwLCBjb2wgPSAiZ3JleSIsIGJnID0gImdyZXkiKSAjIFdlJ3ZlIGxlZnQgdGhlIGF4ZXMgb24KIyBhZGQgdGhlIHJlZ3Jlc3Npb24gbGluZSBmcm9tIHRoZSBtb2RlbCAoZmFpdGhmdWwubG0pIHVzaW5nIGFibGluZS4uLi4uCmFibGluZShmYWl0aGZ1bC5sbSwgY29sPSJibGFjayIpCiMgYWRkIHRoZSBlcXVhdGlvbgp0ZXh0KDk5LDIsICJlcnVwdGlvbnMgPSAwLjA3NTZ3YWl0aW5nICsgLTEuODc0IiwgcG9zID0gMiwgY2V4PTAuNjUpCiMgYWRkIHItc3F1YXJlIHZhbHVlCnRleHQoOTksMS43NSwgZXhwcmVzc2lvbihwYXN0ZShSXjIgPT0gMC44MTA4KSksIHBvcyA9IDIsIGNleCA9IDAuNikgIyBhZGQgaW4gdGV4dCB1c2luZyB0aGUgZXhwcmVzc2lvbi9wYXN0ZSBmdW5jdGlvbnMKIyBjcmVhdGUgYSBzZXF1ZW5jZSBvZiAxMDAwIG51bWJlciBzcGFubmluZyB0aGUgcmFuZ2Ugb2YgaHVtaWRpdGllcyAobWluIHRvIG1heCkKeCA8LSBzZXEobWluKGZhaXRoZnVsJHdhaXRpbmcpLCBtYXgoZmFpdGhmdWwkd2FpdGluZyksIGw9MTAwMCkgICMgbm90aWNlIHRoaXMgaXMgYW4gJ2wnID0gbGVuZ3RoLiBOT1QgYSAxISEhISEhIQojZm9yIGVhY2ggdmFsdWUgb2YgeCwgY2FsY3VsYXRlIHRoZSB1cHBlciBhbmQgbG93ZXIgOTUlIGNvbmZpZGVuY2UKeTwtcHJlZGljdChmYWl0aGZ1bC5sbSwgZGF0YS5mcmFtZSh3YWl0aW5nPXgpLCBpbnRlcnZhbD0iYyIpCiNwbG90IHRoZSB1cHBlciBhbmQgbG93ZXIgOTUlIGNvbmZpZGVuY2UgbGltaXRzCm1hdGxpbmVzKHgseSwgbHR5PTMsIGNvbD0iYmxhY2siKSAjIFRoaXMgZnVuY3Rpb24gYWRkIHRoZSBDSXMsIGx0eSA9IGxpbmUgdHlwZSAoZGFzaGVkKQoKYGBgCiMgIHBsb3Qgd2l0aCBnZ3Bsb3QKYGBge3J9CnAgPC0gZ2dwbG90KGZhaXRoZnVsLCBhZXMoeD13YWl0aW5nLCB5PWVydXB0aW9ucykpICsgCiAgZ2VvbV9wb2ludChjb2wgPSAiZ3JleSIpICsKICBnZW9tX3Ntb290aChtZXRob2Q9bG0sIGNvbCA9ICJibGFjayIpICsgCiAgYW5ub3RhdGUoZ2VvbSA9ICJ0ZXh0IiwgeCA9IDUwLCB5ID0gNiwKICAgICAgICAgICBsYWJlbCA9ICJFcnVwdGlvbnMgPSAtMC4wNzZXYWl0aW5nICsgLTEuODdcbkFkai4gUjIgPSAwLjgxMDgiLAogICAgICAgICAgIGhqdXN0ID0gMCkKcCArIHhsYWIoIldhaXRpbmcgdGltZSBiZXR3ZWVuIGVydXB0aW9ucyAobWlucykiKSArIHlsYWIoIkVydXB0aW9uIGR1cmF0aW9uIChtaW5zKSIpICsgdGhlbWVfYncoKQpgYGAKCiMgUHJlZGljdCBhbmQgcGxvdCB3aXRoIGdncGxvdAoKIyBhZGQgJ2ZpdCcsICdsd3InLCBhbmQgJ3VwcicgY29sdW1ucyB0byBkYXRhZnJhbWUgKGdlbmVyYXRlZCBieSBwcmVkaWN0KQpgYGB7cn0Kb2xkLnByZWRpY3QgPC0gY2JpbmQoZmFpdGhmdWwsIHByZWRpY3QoZmFpdGhmdWwubG0sIGludGVydmFsID0gJ2NvbmZpZGVuY2UnKSkKYGBgCiMgcGxvdCB0aGUgcG9pbnRzIChhY3R1YWwgb2JzZXJ2YXRpb25zKSwgcmVncmVzc2lvbiBsaW5lLCBhbmQgY29uZmlkZW5jZSBpbnRlcnZhbApgYGB7cn0KcCA8LSBnZ3Bsb3Qob2xkLnByZWRpY3QsIGFlcyh3YWl0aW5nLGVydXB0aW9ucykpCnAgPC0gcCArIGdlb21fcG9pbnQoKQpwIDwtIHAgKyBnZW9tX2xpbmUoYWVzKHdhaXRpbmcsIGZpdCkpCnAgPC0gcCArIGdlb21fcmliYm9uKGFlcyh5bWluPWx3cix5bWF4PXVwciksIGFscGhhPTAuMykKcApgYGAKIyAyLiBNdXNzZWwgZGF0YXNldCB1c2luZyBhYnVuZGFuY2UgYXMgYSByZXNwb25zZSB2YXJpYWJsZQojIGxvYWQgZGF0YSBmaWxlCmBgYHtyfQpNdXNzZWwgPC0gcmVhZC5jc3YoZmlsZS5jaG9vc2UoKSkKYGBgCiMgTG9vayBhdCBpdApgYGB7cn0KZ2xpbXBzZShNdXNzZWwpCmBgYAoKUGxvdCBpdCB0byBjaGVjayBmb3IgbGluZWFyaXR5CmBgYHtyfQpzY2F0dGVycGxvdChJTkRJViB+IEFSRUEsIGRhdGEgPSBNdXNzZWwpCmBgYAojIFRoaXMgaW5kaWNhdGVzIHRoYXQgdGhlIGRhdGEgYXJlIG5vdCBub3JtYWx5IGRpc3JpYnV0ZWQgKGVzcGVjaWFsbHkgQVJFQSkKIyBUaGUgYWJ1bmRhbmNlIGRhdGEgZG9uJ3QgbG9vayB0b28gZ29vZCBlaXRoZXIuIEh1Z2UgcGVhayBpbiB0aGUgbWlkZGxlCiMgbWlnaHQgYmUgb3V0bGllcnMgaW4gYm90aCEhISEKCiMgTGV0J3MgZml0IGEgbGluZWFyIG1vZGVsIG5vbmV0aGVsZXNzCmBgYHtyfQptdXNzZWwubG0gPC0gbG0oU1BFQ0lFUyB+IEFSRUEsIGRhdGEgPSBNdXNzZWwpCiMgbG9vayBhdCBpdApzdW1tYXJ5KG11c3NlbC5sbSkKYGBgCiMgQXJlYSBsb29rcyB0byBzaWduaWZpY2FudGx5IHJlbGF0ZWQgdG8gdGhlIG51bWJlciBvZiBtdXNzZWxzCiMgTm93IGNoZWNrIGFzc3VtcHRpb24gYnkgdXNpbmcgUidzIGluYnVpbHQgbW9kZWwgdmFsaWRhdGlvbiBwbG90IGRlZmF1bHRzCiMgc2V0IGdyYXBoaWNzIHBhcmFtZXRlcnMgYmVjYXVzZSB3ZSB3YW50IGFsbCB0aGUgcGxvdHMgb24gb25lIGdyYXBoaWMKYGBge3J9CmF1dG9wbG90KG11c3NlbC5sbSkKYGBgCiMgUmVzaWR1YWxzIHYgRml0dGVkIGluZGljYXRlIGEgcHJvYmxlbS4gSXQncyB3ZWRnZSBzaGFwZWQgYW5kIGh1bXBlZCEKIyBxcXBsb3QgaXMgYSBiaXQgZG9kZ3kgYnV0IG1pZ2h0IGJlIG9rYXkKIyBTY2FsZS1Mb2NhdGlvbiBwbG90IGluZGljYXRlcyBhIHdlZGdlCiMgQ29vayBkaXN0YW5jZSAvIGxldmVyYWdlIGxvb2tzIG9rYXkgLSBidXQgdGhlcmUgYXJlIHNvbWUgbGFyZ2UgdmFsdWVzIGluIGFyZWEKCiMgRklOQUwgVkFMSURBVElPTiBUQVNLIC0gcmVzaWR1YWxzIGFnYWluc3QgZXhwbGFuYXRvcnkgdmFyaWFibGUKYGBge3J9CnBsb3QobXVzc2VsLmxtJHJlc2lkIH4gTXVzc2VsJEFSRUEsCiAgICAgeGxhYiA9ICJNdXNzZWwgYmVkIEFyZWEiLCAKICAgICB5bGFiID0gIlJlc2lkdWFscyIpCmBgYAojIFNvbWUgY29kZSBmb3IgZ2dwbG90IHRvIGRvIHRoZSBzYW1lIHRoaW5nLi4uLi4KYGBge3J9CmdncGxvdChmb3J0aWZ5KG11c3NlbC5sbSwgTXVzc2VsKSwgYWVzKEFSRUEsIC5zdGRyZXNpZCkpICsKICBnZW9tX3BvaW50KCkgKyBnZW9tX3Ntb290aChzZSA9IFRSVUUpCmBgYAojIFRoaXMgaW5kaWNhdGVzIGEgZmV3IGxhcmdlIHZhbHVlcyBhbmQgYSBzbGlnaHQgd2VkZ2UgZHVlIHRvIG51bWVyb3VzIHNtYWxsIHBhdGNoZXMKIyBDb25jbHVzaW9uIHdlIHJlamVjdCB0aGUgbW9kZWwKCiMgU28gd2hhdCBkbyB3ZSBkbz8KIyBXZSBjYW4gbGluZWFyaXNlIHRoZSBleHBsYW5hdG9yeSB2YXJpYWJsZXMgYnkgdHJhbnNmb3JtaW5nIHRoZW0gYW5kIHJlLXJ1biB0aGUgbW9kZWwKIyBJIGFtIG5vdCBhIGZhbiBvZiB0aGlzIC0gd2UnbGwgbG9vayBhdCBvdGhlciBhcHByb2FjaGVzIG5leHQgd2VlayEKIyBhbmQgcmVwZWF0IHRoZSB2YWxpZGF0aW9uCiMgTGV0J3MgZml0IGEgbGluZWFyIG1vZGVsIG5vbmV0aGVsZXNzCmBgYHtyfQptdXNzZWwubG0xIDwtIGxtKFNQRUNJRVMgfiBsb2cxMChBUkVBKSwgZGF0YSA9IE11c3NlbCkKIyBsb29rIGF0IGl0CnN1bW1hcnkobXVzc2VsLmxtMSkKYGBgCiMgTm93IGNoZWNrIGFzc3VtcHRpb24gYnkgdXNpbmcgUidzIGluYnVpbHQgbW9kZWwgdmFsaWRhdGlvbiBwbG90IGRlZmF1bHRzCiMgc2V0IGdyYXBoaWNzIHBhcmFtZXRlcnMgYmVjYXVzZSB3ZSB3YW50IGFsbCB0aGUgcGxvdHMgb24gb25lIGdyYXBoaWMKYGBge3J9CmF1dG9wbG90KG11c3NlbC5sbTEpCmBgYAojIFJlc2lkdWFscyB2IEZpdHRlZCBhcmUgYmV0dGVyIGJ1dCB0aGVyZSBpcyBzdGlsbCBhIGJpdCBvZiB3ZWRnZSBhdCBoaWdoZXIgZml0dGVkIHZhbHVlcwojIHFxcGxvdCBpcyBhIGJldHRlcgojIFNjYWxlLUxvY2F0aW9uIHBsb3QgaW5kaWNhdGVzIGEgc2xpZ2h0IHdlZGdlIHdpdGggaGlnaGVyIHZhbHVlcwojIENvb2sgZGlzdGFuY2UgLyBsZXZlcmFnZSBsb29rcyBpbXByb3ZlZAoKIyBGSU5BTCBWQUxJREFUSU9OIFRBU0sgLSByZXNpZHVhbHMgYWdhaW5zdCBleHBsYW5hdG9yeSB2YXJpYWJsZQpgYGB7cn0KZ2dwbG90KGZvcnRpZnkobXVzc2VsLmxtMSwgTXVzc2VsKSwgYWVzKEFSRUEsIC5zdGRyZXNpZCkpICsKICBnZW9tX3BvaW50KCkgKyBnZW9tX3Ntb290aChzZSA9IEZBTFNFKQpgYGAKIyBUaGlzIGluZGljYXRlcyBhIGZldyBsYXJnZSB2YWx1ZXMgYW5kIGEgc2xpZ2h0IHdlZGdlIGR1ZSB0byBudW1lcm91cyBzbWFsbCBwYXRjaGVzCiMgQ29uY2x1c2lvbiB3ZSByZWplY3QgdGhlIG1vZGVsCgojIFRyeSBsb2cxMCBvbiB0aGUgcmVzcG9uc2UgLSBub3QgdW51c3VhbCB3aXRoIGFidW5kYW5jZSBkYXRhLgojIFRoZXJlIGFyZSBubyB6ZXJvcyBzbyB3ZSBkb24ndCBuZWVkIGFuIG9mZnNldCBvZiAwLjAxIG9yIHNvbWV0aGluZyBzaW1pbGFyCiMgTGV0J3MgZml0IGEgbGluZWFyIG1vZGVsIG5vbmV0aGVsZXNzCmBgYHtyfQptdXNzZWwubG0yIDwtIGxtKGxvZzEwKElORElWKSB+IGxvZzEwKEFSRUEpLCBkYXRhID0gTXVzc2VsKQojIGxvb2sgYXQgaXQKc3VtbWFyeShtdXNzZWwubG0yKQpgYGAKIyBOb3cgY2hlY2sgYXNzdW1wdGlvbiAKYGBge3J9CmF1dG9wbG90KG11c3NlbC5sbTIpCmBgYAojIFJlc2lkdWFscyB2IEZpdHRlZCBhcmUgbXVjaCBiZXR0ZXIgCiMgcXFwbG90IGlzIG9rYXkgLSBzbGlnaHQgaXNzdWUgb24gbG93ZXIgdmFsdWVzCiMgU2NhbGUtTG9jYXRpb24gcGxvdCBpcyBmaW5lCiMgQ29vayBkaXN0YW5jZSAvIGxldmVyYWdlIGxvb2tzIG9rYXkKCiMgRklOQUwgVkFMSURBVElPTiBUQVNLIC0gcmVzaWR1YWxzIGFnYWluc3QgZXhwbGFuYXRvcnkgdmFyaWFibGUKYGBge3J9CmdncGxvdChmb3J0aWZ5KG11c3NlbC5sbTIsIE11c3NlbCksIGFlcyhBUkVBLCAuc3RkcmVzaWQpKSArCiAgZ2VvbV9wb2ludCgpIApgYGAKIyBUaGlzIGlzIGJldHRlciBidXQgc3RpbGwgYSBzbGlnaHQgaHVtcAojIENvbmNsdXNpb24gd2UgYWNjZXB0IHRoZSBtb2RlbAoKIyBwbG90IHRoZSBmaW5hbCBtb2RlbCBpbiBnZ3Bsb3QuLi4KYGBge3J9CnAgPC0gZ2dwbG90KE11c3NlbCwgYWVzKEFSRUEsSU5ESVYpKSArIAogIGdlb21fcG9pbnQoY29sID0gImdyZXkiKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kPWxtLCBjb2wgPSAiYmxhY2siKSArIAogIGFubm90YXRlKGdlb20gPSAidGV4dCIsIHggPSAxMDAwLCB5ID0gMzAsCiAgICAgICAgICAgbGFiZWwgPSAibG9nMTAoSU5ESVYpID0gMC44MzUgKyBsb2cxMChBUkVBKSAtIDAuNTc2XG5bQWRqLiBSMiA9IDAuODEwOF0iLCBoanVzdCA9IDApICAjIGFkZHMgdGV4dCAoTk9URSBcbiBtZWFucyBzdGFydCBuZXcgbGluZSkKcCArIHNjYWxlX3hfY29udGludW91cyh0cmFucyA9ICdsb2cxMCcpICsgc2NhbGVfeV9jb250aW51b3VzKHRyYW5zID0gJ2xvZzEwJykgKyAjIFRoZXNlIGNvbW1hbmRzIHNjYWxlIHRoZSBheGVzCiAgYW5ub3RhdGlvbl9sb2d0aWNrcyhzaWRlcz0ibGIiKSAjIFRoaXMgYWRkcyBsb2cxMCB0aWNrIG1hcmtzCmBgYApOT1RFOiB0aGUgbG9nIGF4ZXMgdXNlIHRoZSBTY2FsZXMgbGlicmFyeSBbc2VlIGFib3ZlXQoKI1Bsb3QgdGhlIGdyYXBoIGFkZCBlcXVhdGlvbnMgaW4gYmFzZSBSCmBgYHtyfQpwbG90KGxvZzEwKElORElWKSB+IGxvZzEwKEFSRUEpLCBkYXRhID0gTXVzc2VsLAogICAgIHhsYWIgPSAiTG9nIE11c3NlbCBjbHVtcCBhcmVhIChtbTIpIiwKICAgICB5bGFiID0gIkxvZyBOdW1iZXIgb2YgSW5kaXZpZHVhbHMiLAogICAgIHBjaCA9IDIxLCBjb2wgPSAiZ3JleSIsIGJnID0gImdyZXkiKSAjIFdlJ3ZlIGxlZnQgdGhlIGF4ZXMgb24KIyBhZGQgdGhlIHJlZ3Jlc3Npb24gbGluZSBmcm9tIHRoZSBtb2RlbCAoZmFpdGhmdWwubG0pIHVzaW5nIGFibGluZS4uLi4uCmFibGluZShtdXNzZWwubG0yLCBjb2w9ImJsYWNrIikKIyBhZGQgdGhlIGVxdWF0aW9uCnRleHQoNC4wLCAxLjQsIGV4cHJlc3Npb24ocGFzdGUoTG9nWzEwXSwgIklORElWID0gMC44MzUiLCBsb2dbMTBdLCAiQVJFQSAtIDAuNTc2IiwgcG9zID0gMikpLCBjZXggPSAuNykKIyBhZGQgci1zcXVhcmUgdmFsdWUKdGV4dCg0LjAsIDEuMywgZXhwcmVzc2lvbihwYXN0ZShSXjIgPT0gMC44NTIpKSwgY2V4ID0gLjcpICMgYWRkIGluIHRleHQgdXNpbmcgdGhlIGV4cHJlc3Npb24vcGFzdGUgZnVuY3Rpb25zCiMgY3JlYXRlIGEgc2VxdWVuY2Ugb2YgMTAwMCBudW1iZXIgc3Bhbm5pbmcgdGhlIHJhbmdlIG9mIGh1bWlkaXRpZXMgKG1pbiB0byBtYXgpCnggPC0gc2VxKG1pbihNdXNzZWwkQVJFQSksIG1heChNdXNzZWwkQVJFQSksIGw9MTAwMCkgICMgbm90aWNlIHRoaXMgaXMgYW4gJ2wnID0gbGVuZ3RoLiBOT1QgYSAxISEhISEhIQojZm9yIGVhY2ggdmFsdWUgb2YgeCwgY2FsY3VsYXRlIHRoZSB1cHBlciBhbmQgbG93ZXIgOTUlIGNvbmZpZGVuY2UKeTwtcHJlZGljdChtdXNzZWwubG0yLCBkYXRhLmZyYW1lKEFSRUE9eCksIGludGVydmFsPSJjIikKI3Bsb3QgdGhlIHVwcGVyIGFuZCBsb3dlciA5NSUgY29uZmlkZW5jZSBsaW1pdHMKbWF0bGluZXMobG9nMTAoeCkseSwgbHR5PTMsIGNvbD0iYmxhY2siKSAjIFRoaXMgZnVuY3Rpb24gYWRkIHRoZSBDSXMsIGx0eSA9IGxpbmUgdHlwZSAoZGFzaGVkKSAKYGBgCiMgYWRkIGluIGdncGxvdCBjb2RlLi4uLgpgYGB7cn0KcCA8LSBnZ3Bsb3QoTXVzc2VsLCBhZXMoeD1sb2cxMChBUkVBKSwgeT1sb2cxMChJTkRJVikpKSArIAogIGdlb21fcG9pbnQoY29sID0gImJsdWUiKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kPWxtLCBjb2wgPSAiYmxhY2siKSArIAogIGFubm90YXRlKGdlb20gPSAidGV4dCIsIHggPSAyLjUsIHkgPSAzLAogICAgICAgICAgIGxhYmVsID0gIkxvZzEwSU5ESVYgPSAwLjgzNSArIGxvZzEwQVJFQSAtIDAuNTc2XG5BZGouIFIyID0gMC44NTIiLAogICAgICAgICAgIGhqdXN0ID0gMCkKcCArIHhsYWIoIkxvZyBNdXNzZWwgY2x1bXAgYXJlYSAobW0yKSIpICsgeWxhYigiTG9nIG51bWJlciBvZiBpbmRpdmlkdWFscyIpCmBgYAojIDMuIEFOQ09WQSBvbiBjb21wZW5zYXRpb24gZGF0YXNldAojIEp1c3Qgc28geW91IGhhdmUgYSBmcmFtZSBvZiByZWZlcmVuY2UgZ29pbmcgZm9yd2FyZDsKIyB0aGUgY29tcGVuc2F0aW9uIGRhdGEgYXJlIGFib3V0IHRoZSBwcm9kdWN0aW9uIG9mIGZydWl0IChhcHBsZXMsIGtnKSAKIyBvbiByb290c3RvY2tzIG9mIGRpZmZlcmVudCB3aWR0aHMgKG1tOyB0aGUgdG9wcyBhcmUgZ3JhZnRlZCBvbnRvIHJvb3RzdG9ja3MpLiAKIyBGdXJ0aGVybW9yZSwgc29tZSB0cmVlcyBhcmUgaW4gcGFydHMgb2YgdGhlIG9yY2hhcmQgdGhhdCBhbGxvdyBncmF6aW5nIGJ5IGNhdHRsZSwgCiMgYW5kIG90aGVycyBhcmUgaW4gcGFydHMgZnJlZSBmcm9tIGdyYXppbmcuIEdyYXppbmcgbWF5IHJlZHVjZSB0aGUgYW1vdW50IG9mIGdyYXNzLCAKIyB3aGljaCBtaWdodCBjb21wZXRlIHdpdGggdGhlIGFwcGxlIHRyZWVzIGZvciByZXNvdXJjZXMuCgojIExvYWQgZmlsZQpgYGB7cn0KQ29tcGVuc2F0aW9uIDwtIHJlYWQuY3N2KGZpbGUuY2hvb3NlKCkpCmBgYAojIGxvb2sgYXQgZGF0YQpgYGB7cn0Kc3RyKENvbXBlbnNhdGlvbikKYGBgCgpgYGB7cn0KQ29tcGVuc2F0aW9uJEdyYXppbmcgPC0gYXMuZmFjdG9yKENvbXBlbnNhdGlvbiRHcmF6aW5nKSAjIFdlIG5lZWQgdGhpcyB0byBiZSBhIGZhY3RvciBmb3IgYW4gQU5DT1ZBCmBgYApQbG90IGl0CmBgYHtyfQojIFBsb3QgaXQuLi4uCnBsb3QoRnJ1aXQgfiBSb290LCBkYXRhID0gQ29tcGVuc2F0aW9uLCBwY2ggPSAxOSxjZXggPSAxLjUsCiAgICAgY29sID0gYygiQmxhY2siLCAiUmVkIilbQ29tcGVuc2F0aW9uJEdyYXppbmddLAogICAgIHhsYWIgPSBsaXN0KCJSb290IGJpb21hc3MgKG1tKSIsIGNleCA9IDEuMiksCiAgICAgeWxhYiA9IGxpc3QoIkZydWl0IFByb2R1Y3Rpb24gKGtnKSIsIGNleCA9IDEuMikpCiMgTm93IGFkZCBhIGxlZ2VuZApsZWdlbmQoNSwgMTE1LCBsZWdlbmQgPSBjKCJHcmF6ZWQiLCAiVW5ncmF6ZWQiKSwKICAgICAgIGNvbCA9IGMoImJsYWNrIiwgInJlZCIpLCBwY2ggPSAxOSkKYGBgCgpPciBpbiBjb3Bsb3QKYGBge3J9CmNvcGxvdChSb290fiBGcnVpdCB8IEdyYXppbmcsIGRhdGEgPUNvbXBlbnNhdGlvbikgIyBHcmF6ZWQgcGxhbnRzIGhhdmUgaGlnaGVyIHJvb3QgYmlvbWFzcy4gCgpgYGAKIyBZb3UgY2FuIGRvIHRoaXMgaXMgbGF0dGljZSB0b28KYGBge3J9CmJveHBsb3QoUm9vdCB+IEdyYXppbmcsIGRhdGEgPSBDb21wZW5zYXRpb24pICMgVGhlc2UgbG9vayBmaW5lCmJveHBsb3QoRnJ1aXQgfiBHcmF6aW5nLCBkYXRhID0gQ29tcGVuc2F0aW9uKSMgVGhlc2UgbG9vayBmaW5lCmBgYAojIFlvdSBtaWdodCBhbHNvIGRvIHNvbWUgUVEtcGxvdHMgaGVyZS4uLi4ub3IgcGxvdCB0byBjaGVjayBob21vZ2VuZWl0eSBvZiB2YXJpYW5jZXMgCiMgYnV0IHdlJ2xsIGxlYXZlIHRoYXQgZm9yIHZhbGlkYXRpb24uLi4uCgojIFJ1biBBTkNPVkEKYGBge3J9CkNvbXBlbnNhdGlvbi5sbSA8LSBsbShGcnVpdCB+ICBHcmF6aW5nKlJvb3QsIGRhdGE9Q29tcGVuc2F0aW9uKSAKYGBgCiMgVmFsaWRhdGUgbW9kZWwgdG8gY2hlY2sgYXNzdW1wdGlvbnMKYGBge3J9CmF1dG9wbG90KENvbXBlbnNhdGlvbi5sbSkKYGBgCiMgVGhpcyBsb29rcyBwcmV0dHkgZGVjZW50LiBTbGlnaHQgY29uY2VybiBvdmVyIFFRLXBsb3QgYnV0IGl0J3Mgbm90IGEgbWFzc2l2ZSBwcm9ibGVtLgoKI0xvb2sgYXQgbW9kZWwgb3V0Y29tZXMKYGBge3J9CmFub3ZhKENvbXBlbnNhdGlvbi5sbSkKYGBgCiMgQW5vdmEgc2hvd3MgdGhhdCBib3RoIFJvb3QgYW5kIEZydWl0IGFyZSBzaWduaWZpY2FudCB0ZXJtcwojIEJ1dCB0aGF0IHRoZSBpbnRlcmFjdGlvbiBpc24ndC4uLi4KCmBgYHtyfQpzdW1tYXJ5KENvbXBlbnNhdGlvbi5sbSkgCmBgYAojIERhdGEgaW5kaWNhdGUgZnJ1aXQgZGlmZmVycyBieSBncmF6aW5nIAojIE5vIGludGVyYWN0aW9uIHRlcm0gaS5lLiBzbG9wZSBmb3IgZmFjdG9yIEdyYXppbmcgYXJlIHRoZSBzYW1lCiMgTG9vayBhdCB0aGUgZXhhbXBsZSBpbiB0aGUgbGVjdHVyZSA2IHRvIGZpZ3VyZSBvdXQgdGhlIGludGVyY2VwdCBhbmQgc2xvcGUgZGlmZmVyZW5jZXMsIGJ1dCBoZXJlIHdlIGdvOgoKIyBUaGUgaW50ZXJjZXB0IChmaXJzdCByb3cgaW4gdGhlIHN1bW1hcnkgb3V0cHV0KSBpcyB0aGUgaW50ZXJjZXB0IGZvciBncmF6ZWQgc2FtcGxlcyBiZWNhdXNlIGdyYXplZCAoaS5lIEcpCiMgY29tZXMgYmVmb3JlIHVuZ3JhemVkIChpLmUuIFUpIGluIHRoZSBhbHBoYWJldCBhbmQgUiB1c2VzIGFuIGFscGhhbnVtZXJpYyBjYWxsIG9uIGZhY3RvciBkYXRhLiAKIyBUaGUgMm5kIGxpbmUgR3JhemluZ1VuZ3JhemVkIGlzIHRoZSBkaWZmZXJlbmNlIGluIHRoZSBpbnRlcmNlcHRzLiBTbyBVbmdyYXplZCBpcyAzMC44MDYgbGFyZ2VyLiBNZWFuaW5nIDMwLjggbW9yZSBzZWVkcyBhcmUgcHJvZHVjZWQgYnkgZ3JhemVkIHBsYW50cwojIENhbGN1bGF0ZSB0aGUgaW50ZXJjZXB0IGZvciBVbmdyYXplZApgYGB7cn0KLTEyNS4xNzMgICsgMzAuODA2ICMgPSAtOTQuMzY3CmBgYAojIHRoZSB0aGlyZCBsaW5lIGlzIHNsb3BlIGZvciByb290CiMgdGhlIGZvdXJ0aCBsaW5lIEdyYXppbmdVbmdyYXplZDpSb290IGlzIHRoZSBkaWZmZXJlbmNlIGluIHNsb3BlcyBiZXR3ZWVuIEdyYXplZCBhbmQgVW5ncmF6ZWQgPSAwLjc1Niwgd2hpY2ggaXMgdGlueQoKIyB0aGUgY29lZmZpY2llbnRzIHNob3cgdGhpcy4uLi4KYGBge3J9CmNvZWYoQ29tcGVuc2F0aW9uLmxtKQpgYGAKIyBOb3cgbGV0cyBhZGQgbGluZXMgdG8gdGhlIGdyYXBocy4gV2UgY2FuIGRvIGl0IG1hbnkgd2F5cyAtIHNvIGhlcmUgaXMgYW5vdGhlciBvbmUhCiMgUm91dGUgb25lIC0gdXNpbmcgYWJsaW5lCmBgYHtyfQpwbG90KEZydWl0IH4gUm9vdCwgZGF0YSA9IENvbXBlbnNhdGlvbiwgcGNoID0gMTksY2V4ID0gMS41LAogICAgIGNvbCA9IGMoIkJsYWNrIiwgIlJlZCIpW0NvbXBlbnNhdGlvbiRHcmF6aW5nXSwKICAgICB4bGFiID0gbGlzdCgiUm9vdCBiaW9tYXNzIChtbSkiLCBjZXggPSAxLjIpLAogICAgIHlsYWIgPSBsaXN0KCJGcnVpdCBwcm9kdWN0aW9uIChrZykiLCBjZXggPSAxLjIpKQojIE5vdyBhZGQgYSBsZWdlbmQKbGVnZW5kKDUsIDExNSwgbGVnZW5kID0gYygiR3JhemVkIiwgIlVuZ3JhemVkIiksCiAgICAgICBjb2wgPSBjKCJibGFjayIsICJyZWQiKSwgcGNoID0gMTkpCiMgYWRkIGFibGluZXMuLi4ud2UnbGwgZG8gaXQgbWFudWFsbHkgdXNpbmcgdGhlIHNsb3BlcyBhbmQgaW50ZXJjZXB0cyBidXQgeW91IGNhbiB1c2UgY29lZmY3KCkgc2VlIGJlbG93LgphYmxpbmUoLTEyNS4xNzMsIDIzLjI0MCkKYWJsaW5lKC0xMjUuMTczKzMwLjgwNSwgMjMuMjQwKzAuNzU2LCBjb2w9ICJyZWQiKQpgYGAKIyBQbG90IHVzaW5nIGNvZWZmaWNpZW50cwpgYGB7cn0KQ29tcGVuc2F0aW9uLmxtJGNvZWZmWzFdICMgcmVncmVzc2lvbiBjb2VmZmljaWVudCBmb3IgZ3JhemVkIGludGVyY2VwdApDb21wZW5zYXRpb24ubG0kY29lZmZbMl0gIyByZWdyZXNzaW9uIGNvZWZmaWNpZW50IGZvciBncmF6ZWQgc2xvcGUKQ29tcGVuc2F0aW9uLmxtJGNvZWZmWzNdICMgcmVncmVzc2lvbiBjb2VmZmljaWVudCBmb3IgZGlmZiBpbiBncmF6ZWQvdW5ncmF6ZWQgaW50ZXJjZXB0CkNvbXBlbnNhdGlvbi5sbSRjb2VmZls0XSAjIHJlZ3Jlc3Npb24gY29lZmZpY2llbnQgZm9yIGRpZmYgaW4gZ3JhemVkL3VuZ3JhemVkIHNsb3BlCnBsb3QoRnJ1aXQgfiBSb290LCBkYXRhID0gQ29tcGVuc2F0aW9uLCBwY2ggPSAxOSxjZXggPSAxLjUsCiAgICAgY29sID0gYygiQmxhY2siLCAiUmVkIilbQ29tcGVuc2F0aW9uJEdyYXppbmddLAogICAgIHhsYWIgPSBsaXN0KCJSb290IGJpb21hc3MgKG1tKSIsIGNleCA9IDEuMiksCiAgICAgeWxhYiA9IGxpc3QoIkZydWl0IFByb2R1Y3Rpb24gKGtnKSIsIGNleCA9IDEuMikpCiMgTm93IGFkZCBhIGxlZ2VuZApsZWdlbmQoNSwgMTE1LCBsZWdlbmQgPSBjKCJHcmF6ZWQiLCAiVW5ncmF6ZWQiKSwKICAgICAgIGNvbCA9IGMoImJsYWNrIiwgInJlZCIpLCBwY2ggPSAxOSkKIyBhZGQgYWJsaW5lcy4uLi51c2luZyBjb2VmZmljaWVudHMgLSBjb2VmZigpCmFibGluZShjb2VmKENvbXBlbnNhdGlvbi5sbSlbMV0sIGNvZWYoQ29tcGVuc2F0aW9uLmxtKVszXSkgCiMgTm93IGFkZCB0aGUgc3VtbWVyIHJlZ3Jlc3Npb24gbGluZQphYmxpbmUoY29lZihDb21wZW5zYXRpb24ubG0pWzFdICsgY29lZihDb21wZW5zYXRpb24ubG0pWzJdLAkKICAgICAgIGNvZWYoQ29tcGVuc2F0aW9uLmxtKVszXSArIGNvZWYoQ29tcGVuc2F0aW9uLmxtKVs0XSwJCiAgICAgICBjb2wgPSAicmVkIikKYGBgCiMgZG8gc29tZSBwcmVkaWN0aW9uLi4uLmFuZCBwbG90Li4uLnRoaXMgaXMgeWV0IGFub3RoZXIgd2F5IG9mIGRvaW5nIGl0CiNwcm9kdWNlIGJhc2UgcGxvdCAKYGBge3J9CnhzIDwtIHNlcSgwLCAxMiwgbCA9IDEwMCkKcGxvdChGcnVpdCB+IFJvb3QsIGRhdGEgPSBDb21wZW5zYXRpb24sIHhsYWIgPSAiUm9vdCBiaW9tYXNzIChtbSkiLCB5bGFiID0gIkZydWl0IFByb2R1Y3Rpb24gKGtnKSIpCiMgUGxvdCB0aGUgcG9pbnRzIGFuZCBwcmVkaWN0ZWQgdHJlbmRzICh1c2luZyBzZSkKcG9pbnRzKEZydWl0IH4gUm9vdCwgZGF0YSA9IENvbXBlbnNhdGlvbiwgc3Vic2V0ID0gR3JhemluZyA9PSAiR3JhemVkIiwgcGNoID0gMTkpCnByZWQgPC0gcHJlZGljdChDb21wZW5zYXRpb24ubG0sIHR5cGUgPSAicmVzcG9uc2UiLCBzZSA9IFRSVUUsIG5ld2RhdGEgPSBkYXRhLmZyYW1lKFJvb3QgPSB4cywgR3JhemluZyA9ICJHcmF6ZWQiLCBSb290ID0gbWVhbihDb21wZW5zYXRpb24kUm9vdCkpKQpsaW5lcyhwcmVkJGZpdCB+IHhzKQpwb2ludHMoRnJ1aXQgfiBSb290LCBkYXRhID0gQ29tcGVuc2F0aW9uLCBzdWJzZXQgPSBHcmF6aW5nID09ICJVbmdyYXplZCIsIHBjaCA9IDE5LCBjb2wgPSAicmVkIikKcHJlZCA8LSBwcmVkaWN0KENvbXBlbnNhdGlvbi5sbSwgdHlwZSA9ICJyZXNwb25zZSIsIHNlID0gVFJVRSwgbmV3ZGF0YSA9IGRhdGEuZnJhbWUoUm9vdCA9IHhzLCBHcmF6aW5nID0gIlVuZ3JhemVkIiwgUm9vdCA9IG1lYW4oQ29tcGVuc2F0aW9uJFJvb3QpKSkKbGluZXMocHJlZCRmaXQgfiB4cywgY29sID0gInJlZCIpCmxlZ2VuZCgidG9wbGVmdCIsIGxlZ2VuZCA9IGMoIkdyYXplZCIsICJVbmdyYXplZCIpLCBwY2ggPSBjKDE5LCAxOSksIGNvbCA9IGMoInJlZCIsImJsYWNrIiksIHRpdGxlID0gIkZydWl0IFByb2R1Y3Rpb24iLCBidHkgPSAibiIpCmJveChidHkgPSAibCIpCmBgYAojIFBsb3QgdGhlIHBvaW50cyBhbmQgcHJlZGljdGVkIHRyZW5kcyAodXNpbmcgZ2dwbG90MikuIEEgZmFpciBiaXQgZWFzaWVyLi4uLi5OT1RFIC0geW91J2QgbmVlZCB0byB0aWR5IHVwIHRoZSBsYWJlbHMgYW5kIHRoZSBsaWtlLi4uCmBgYHtyfQpnZ3Bsb3QoQ29tcGVuc2F0aW9uLCBhZXMoeD1Sb290LCB5PUZydWl0LCBjb2xvcj1mYWN0b3IoR3JhemluZykpKSArCiAgZ2VvbV9wb2ludCgpICsgCiAgZ2VvbV9zbW9vdGgobWV0aG9kPWxtKQpgYGA=